<?php
class SP_Database_ModelRecord
{
	private $base_name;
	private $root;
	private $reader;
	private $writer;
	private $table_name;
	private $name;
	private $primary = 'Id';
	private $is_saved = false;
	private $is_new = true;
	private $fields = array();
	
	public function defineField(SP_Database_Field $field)
	{
		$name=$field->getModelName();
		if( $this->hasField($name) ) throw new excepton('Field with name "'.$name.'" already exist');
		$this->fields[$name]=$field;
		return $this;
	}
	
	public function hasField($name)
	{
		return isset($this->fields[$name]);
	}
	
	public function takeField($name)
	{
		if( !$this->hasField($name) ) throw new exception('Record class "'.$this->name.'" has not "'.$name.'" field');
		return $this->fields[$name];
	}

	public function set($name,$value)
	{
		$field=$this->takeField($name);
		if( !$field->setValue($value) ) return $field->getValidateErrors();
		$this->is_saved = false;
		return true;
	}
	
	public function get($name)
	{
		$field=$this->takeField($name);
		return $field->getValue();
	}
	
	public function __call($name,$values=null)
	{
		if( strlen($name) > 3 )
		{
			$value=$values[0];
			$method=strtolower(substr($name,0,3));
			$field_name=substr($name,3);
			if( $method=='set' )
			{
				return $this->set($field_name, $value);
			}
			elseif( $method=='get' )
			{
				return $this->get($field_name);
			}
		}
	}

	public function validateValues()
	{
		foreach($this->fields as $field)
		{
			if( !$field->validate() ) return false;
		}
		return true;
	}
	
	public function save()
	{
		$base=$this->takeWriter();
		$to_save=array();
		foreach($this->fields as $field) //формируем массив для сохранения
		{
			$to_save[$field->getBaseName()]=$field->getValue();
		}
		unset($to_save[$this->takeField($this->primary)->getBaseName()]); //удаляем из сохранения id поле
		if( $this->isNew() ) // запись новая - делаем INSERT
		{
			$base->query(SP_Database_QueryBuilder::insert($this->takeTableName(),$to_save));
			if( $base->getResult() ) //если успешно вставилось
			{
				$this->takeField('id')->setValue($base->getLastInsertId());
				$this->is_new=false;
				return true;
			}
			return false;
		}
		else //запись уже сохранена в базе - делаем UPDATE
		{
			foreach($this->fields as $field) //удаляем поля, которые не были изменены
			{
				if( !$field->getWasModified() ) unset($to_save[$field->getBaseName()]);
			}
			if( count($to_save)==0 ) return true; //если измененных полей ноль - возвращаем тру
			$where[$this->takeField('id')->getBaseName()]=$this->takeField('id')->getValue();
			$base->query(SP_Database_QueryBuilder::update($this->takeTableName(),$to_save,$where,1));
			return (bool)$base->getResult();
		}
	}
	
	public function delete()
	{
		if( $this->isNew() ) return false;
		$base=$this->takeWriter();
		$query="DELETE FROM `".$this->takeTableName()."` WHERE `".$this->takeField($this->primary)->getBaseName()."`='".$this->takeField($this->primary)->getValue()."' LIMIT 1";
		$base->query($query);
		if ( $base->getResult() )
		{
			$this->is_new=true;
			return true;
		}
		return false;
	}
	
	public function turnOffValidation()
	{
		foreach($this->fields as $field)
		{
			$field->setNeedValidate(false);
		}
	}
	
	public function turnOnValidation()
	{
		foreach($this->fields as $field)
		{
			$field->setNeedValidate(true);
		}
	}
	
	public function fromRow($row)
	{
		foreach($this->fields as $field)
		{
			$field->setValueForce($row[$field->getBaseName()]);
		}
		$this->is_new = false;
		$this->is_saved = true;
	}
	
	public function readWhere($where, $native_sql=true)
	{
		if ($native_sql)
		{
			$base=$this->takeReader();
			$this->fromRow($base->getAssocRow("SELECT * FROM `".$this->table_name."` WHERE $where LIMIT 1"));
			if( $base->getResult() ) $this->is_saved=true;
			return (bool)$base->getResult();
		}
	}
	
	public function readById($id)
	{
		if (!SP_Helpers_Checker::checkID($id)) return false;
		return $this->readWhere("`".$this->fields[$this->primary]->getBaseName()."`='$id'");
	}
	
	public function definePrimary($name)
	{
		$this->primary=$name;
		return $this;
	}	

	public function takePrimaryField()
	{
		return $this->takeField($this->primary);
	}	
	
	public function defineName($value)
	{
		$this->name=$value;
		$array=SP_Common_Functions::splitCamelCase($value);
		$this->table_name=SP_Common_Functions::arrayToString($array, $glue='_');
		return $this;
	}
	
	public function takeName()
	{
		return $this->name;
	}
	
	public function defineTableName($value)
	{
		$this->table_name=$value;
		return $this;
	}
	
	public function takeTableName()
	{
		return $this->table_name;
	}
	
	public function defineBaseName($value)
	{
		$this->base_name = $value;
		return $this;
	}
	
	private function takeReader()
	{
		if( empty($this->reader) )
		{
			if( !SP_Database_BaseCollector::hasBase($this->base_name) ) throw new exception('Database "'.$this->base_name.'" not found');
			$this->reader=SP_Database_BaseCollector::getBase($this->base_name)->getReader();
		}
		return $this->reader;
	}
	
	private function takeWriter()
	{
		if( empty($this->writer) )
		{
			if( !SP_Database_BaseCollector::hasBase($this->base_name) ) throw new exception('Database "'.$this->base_name.'" not found');
			$this->writer=SP_Database_BaseCollector::getBase($this->base_name)->getWriter();
		}
		return $this->writer;
	}

	public function isNew()
	{
		return $this->is_new;
	}
	
	public function isSaved()
	{
		return $this->is_saved;
	}
	
	public function unsetValues()
	{
		foreach($this->fields as $field)
		{
			$field->unsetValue();
		}
	}
	
}